package com.zhangjunkai.net
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;

	/**
	 * 专门用来传送紧密型消息的Socket
	 * @author ZJK
	 */
	public class TightMessageSocket extends Socket
	{
		private var _eventFun:Function;
		private var _dataFun:Function;
		private var _closedFun:Function;
		private var _tightMessageProcess:TightMessageProcess;
		private var _socketTempByteArray:ByteArray;
		private var _clientSocket:Socket;

		/**
		 * 创建一个专门用来传送紧密型消息的Socket
		 * @param eventFun socket的事件(包括Event.CONNECT,IOErrorEvent.IO_ERROR,SecurityErrorEvent.SECURITY_ERROR)将调用此方法 此方法必须有一个参数 fun(event:Event)
		 * @param dataFun 有具体数据解析成功时 调用此方法 此方法必须有两个参数 fun(tightMessageSocket:TightMessageSocket,arr:Array)
		 * @param closedFun socket关闭时 调用此方法 此方法必须有两个参数 fun(tightMessageSocket:TightMessageSocket,event:Event)
		 * @param arc4key 传输的消息是否加密 (默认不加密)
		 * @param clientSocket 是否是对已有的socket进行包装?(默认=null)
		 * @param listener_IOErrorEvent 是否监听IOErrorEvent事件(默认=true) 如果是对已有的socket进行包装 推荐传参false
		 * @param listener_SecurityErrorEvent 是否监听SecurityErrorEvent事件(默认=true) 如果是对已有的socket进行包装 推荐传参false
		 */
		public function TightMessageSocket(eventFun:Function, dataFun:Function, closedFun:Function, arc4key:ByteArray=null, clientSocket:Socket=null, listener_IOErrorEvent:Boolean=true, listener_SecurityErrorEvent:Boolean=true)
		{
			_socketTempByteArray=new ByteArray();

			_eventFun=eventFun;
			_dataFun=dataFun;
			_closedFun=closedFun;
			_clientSocket=clientSocket;

			_tightMessageProcess=new TightMessageProcess(arc4key);

			if (clientSocket != null)
			{
				start(clientSocket);
			}
			else
			{
				start(this);
			}

			function start(socket:Socket):void
			{
				socket.addEventListener(Event.CLOSE, closeHandler);
				socket.addEventListener(Event.CONNECT, connectHandler);
				socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);

				if (listener_IOErrorEvent)
				{
					socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
				}
				if (listener_SecurityErrorEvent)
				{
					socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
				}
			}
		}

		/**
		 * 关闭事件
		 * @param event
		 */
		private function closeHandler(event:Event):void
		{
			_closedFun.call(null, this, event);
		}

		/**
		 * 连接成功
		 * @param event
		 */
		private function connectHandler(event:Event):void
		{
			_eventFun.call(null, event);
		}

		/**
		 * IO错误
		 * @param event
		 */
		private function ioErrorHandler(event:Event):void
		{
			_eventFun.call(null, event);
		}

		/**
		 * 沙箱错误
		 * @param event
		 */
		private function securityErrorHandler(event:Event):void
		{
			_eventFun.call(null, event);
		}

		/**
		 * 收到消息
		 * @param event
		 */
		private function socketDataHandler(progressEvent:ProgressEvent):void
		{
			var socket:Socket=progressEvent.target as Socket;
			var tempByte:ByteArray;

			tempByte=new ByteArray();
			while (socket.bytesAvailable)
			{
				socket.readBytes(tempByte);
			}
			_socketTempByteArray.position=_socketTempByteArray.length;
			_socketTempByteArray.writeBytes(tempByte);
			_socketTempByteArray.position=0;
			//将socket中的数据全部读入到socketTempByteArray中

			while (_socketTempByteArray.bytesAvailable >= 1)
			{
				var packLength:int=_socketTempByteArray.readUnsignedByte(); //只是包头位置的改变 其实数据并没有因为read而减少
				if (_socketTempByteArray.bytesAvailable >= packLength) //如果够读取一个包长度的数据
				{
					tempByte=new ByteArray();
					_socketTempByteArray.readBytes(tempByte, 0, packLength);
					var messageArr:Array=new Array();
					_dataFun.call(null, this, _tightMessageProcess.decode(tempByte));
					tempByte=new ByteArray();
					_socketTempByteArray.readBytes(tempByte);
					_socketTempByteArray=tempByte;
					_socketTempByteArray.position=0;
				}
				else
				{
					_socketTempByteArray.position=0;
					break;
				}
			}
		}

		/**
		 * 发送消息
		 * @param arr
		 */
		public function send(arr:Array):void
		{
			if (_clientSocket != null)
			{
				_clientSocket.writeBytes(_tightMessageProcess.encode(arr));
				_clientSocket.flush();
			}
			else
			{
				this.writeBytes(_tightMessageProcess.encode(arr));
				this.flush();
			}
		}

		/**
		 * 清理本TightMessageSocket 此后本对象将不在被使用
		 */
		public function clear():void
		{
			var socket:Socket=_clientSocket == null ? this : _clientSocket;
			socket.removeEventListener(Event.CLOSE, closeHandler);
			socket.removeEventListener(Event.CONNECT, connectHandler);
			socket.removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
			socket.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			_clientSocket=null;
			_eventFun=null;
			_dataFun=null;
			_closedFun=null;
			_tightMessageProcess=null;
			_socketTempByteArray.clear();
			_socketTempByteArray=null;
		}
	}
}
